home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr10 / bagtag2.zip / CTAGS.CB < prev    next >
Lisp/Scheme  |  1992-11-17  |  17KB  |  502 lines

  1. /****************************************************************************
  2. *
  3. *   ctags.cb                                            17Nov92
  4. *
  5. *   File:  ctags.cb 8/24/85
  6. *   Written by: Yellow Pig XVII
  7. *   Modified by: The Shaman 08/07/90
  8. *   Modified by: BAG 22Oct92
  9. *
  10. *   Contains entries:
  11. *       _init
  12. *       tag
  13. *       ctag
  14. *       locate_in_file
  15. *       parse_tag_line
  16. *
  17. *   BRIEF macros to do vi-like tag.  Assumes the existence of a file
  18. *   called (TAGFILE) which can be created using the "ctags" utility.  If
  19. *   this file doesn't exist, tag is simply reported as "Not found."
  20. *   The format of each line of the tags file must be:
  21. *
  22. *   tagword filename ?<pattern>?
  23. *
  24. *   This is the normal output produced by the Unix utility "ctags".
  25. *
  26. *   For those unfamiliar with tagging, it is really useful.  If you
  27. *   create a tags file for all your C source files you can locate the
  28. *   file and line where a given function is declared when you're in
  29. *   the editor, even if that function is declared in a different
  30. *   source file from the one you are editing. Tagging will move you
  31. *   to that line in that file.
  32. *
  33. *   tag <identifier>:
  34. *    To use these BRIEF macros, you can call "tag" directly as a
  35. *    command. It will ask you to enter a tag. Give the name of the
  36. *    function you are searching for (case sensitivity will depend on
  37. *    the current setting in your editing session).  Or you can assign
  38. *    the macro "ctag" to a key. If you do this, you can place the
  39. *    cursor anywhere on the name of a function you wish to tag to
  40. *    (presumably an occurrence of it where it is being called, but
  41. *    this is not necessary -- you can tag to a function if you are
  42. *    already there!!) and hit the key you assigned.
  43. *
  44. *   tag { /first | /last | /next | /prev | /clear }
  45. *    Move to the corresponding file in the chronological list of
  46. *    identifiers tagged to, or clear the list.
  47. *
  48. *   ctag:
  49. *    Checks to make sure cursor is on a valid function name.  A valid
  50. *    function name is considered to be any string of alphanumeric
  51. *    characters (including the underscore) which begins with a letter.
  52. *
  53. *   If the tag is invalid, the cursor position remains the same.
  54. *    Otherwise the full word is read and passed to "tag".
  55. *
  56. *   Macro goto.cb hooks these into the same Alt-g key normally used for
  57. *    goto_line: 
  58. *       if a numeric value is entered, it acts like goto_line
  59. *       if a non-numeric string "foo" is entered, it acts like tag foo
  60. *       if Enter is hit, it acts like ctag
  61. *       Esc kills the command
  62. *
  63. *   Changes/Additions by Michael Denio 5/15/90
  64. *   ------------------------------------------
  65. *    The program now looks for all CTAGS.TAG files specified in directories
  66. *     in the CTAGS environment variable.  It first looks in the current
  67. *     directory. Example:  set CTAGS=C:\;N:\LIB\SRC;
  68. *    Place the following in your initials file:
  69. *     (autoload "ctags" "ctag" "tag")
  70. *    You can then assign a key to ctag and tag macros.
  71. *
  72. *   Changes/Additions by The Shaman 08/07/90
  73. *   ----------------------------------------
  74. *    Added TAGFILE define when searching the current path.
  75. *    Changed path search so that it is done sequentially as in DOS
  76. *     rather than by reading contents of all tag files into a
  77. *     buffer before doing a search on the tag.
  78. *    Added appropriate message displays while tagging.
  79. *    Made read_word function and string searches more efficient.
  80. *
  81. *   Changes/Additions by Edward Diener 7/14/92 Compuserve 70304,2632
  82. *   ----------------------------------------------------------------
  83. *    (Taken from ctags5.zip from Borland-Brief Forum on CompuServe)
  84. *    He added something on the order of keeping a list of files tagged to,
  85. *     allowing one to page forward and backward through the list. BUT,
  86. *     he had some scheme of FROM and TO positions and stopping at this or
  87. *     that, which makes no sense to me. But I'll steal the underlying idea.
  88. *     See change notes below and doc above re
  89. *               tag { /first | /last | /next | /prev | /clear }
  90. *     in addition to the basic
  91. *               tag <identifier>
  92. *
  93. *   Things to add, think about, etc.
  94. *   --------------------------------
  95. *    "Automatically" (i.e., under certain circumstances) call ctags.com to
  96. *     generate the tag file?
  97. *
  98. *   Copyright (c) 1992 B. Goldstein -- Pequod Software
  99. *
  100. *   Change History
  101. *   Date    Who What
  102. *   ------- --- ---------------------
  103. *   22Oct92 BAG Dropped The Shaman's thing about stripping braces
  104. *                   from search pattern (I think he should have done the
  105. *                   escape-re thing that I added to ctags.c)
  106. *               Changed name of macro from tags.cb to ctags.cb
  107. *   22Oct92 BAG Dropped cch from read_word, etc.
  108. *   22Oct92 BAG Bug in find_word, in search_fwd pattern
  109. *   24Oct92 BAG read_word identifier scan included one too many characters
  110. *   27Oct92 BAG Added /first | /last | /next | /prev | /clear options to tag
  111. *   28Oct92 BAG Dropped file name from messages (it's always TAGFILE); left
  112. *                   pathname
  113. *   28Oct92 BAG Replaced ctag search (let's stay on same line, at least)
  114. *   28Oct92 BAG And that means there's not much need for read_word at all
  115. *   28Oct92 BAG And locate_in_file doesn't need any argument, since it uses
  116. *                   the found file name locally
  117. *   28Oct92 BAG But since tag lines need to be parsed for chaining and for
  118. *                   original tagging, added parse_tag_line routine
  119. *   17Nov92 BAG Altered search for TAGFILE: First current directory, then
  120. *                   directory of file being edited, then CTAGS path
  121. *   17Nov92 BAG Added scan of keyboard to abort scan between directories
  122. *
  123. ****************************************************************************/
  124.  
  125. /* Definitions */
  126. #define TAGENV  "CTAGS"         // CTAGS environment variable
  127. #define TAGFILE "CTAGS.TAG"     // CTAGS filename
  128.  
  129. //---------------------------------------------------------------------------
  130.  
  131. /* Info for moving around tagged files */
  132. int tag_chain_buffer;    // Buffer for holding tag chaining info
  133. int tag_chain_line;      // Current line in buffer
  134.  
  135. //---------------------------------------------------------------------------
  136.  
  137. /* Prototypes */
  138. void _init (void);
  139. void tag (string);
  140. void ctag (void);
  141. void locate_in_file (void);
  142. void parse_tag_line (string tag_line, string the_file, string pattern);
  143. string GetIdentifier (~string);
  144.  
  145. //---------------------------------------------------------------------------
  146.  
  147. /* External references */
  148. extern center_line (void);
  149.  
  150. /***************************************************************************/
  151.  
  152. /*  _init                                   */
  153. /*                                          */
  154. /*  Create system buffer for tag chaining   */
  155. /*                                          */
  156.  
  157. void _init (void)
  158.  
  159.  {
  160.     tag_chain_buffer = create_buffer ("tagsave", NULL, 1);  // SYSTEM_BUFF
  161.  
  162.     return;
  163.  }
  164.  
  165. //---------------------------------------------------------------------------
  166.  
  167. /*   tag                                                                   */
  168. /*                                                                         */
  169. /*   Looks in tags file for given tag, gets the filename and search        */
  170. /*   pattern to use in locating the tag, edits the given file and          */
  171. /*   searches for the pattern.  If the tag isn't found, reports an         */
  172. /*   error.  There is no error checking in this macro for a valid          */
  173. /*   function name (tag).   This macro will most often be used in          */
  174. /*   conjunction with the "ctag" macro which does this error checking.     */
  175. /*                                                                         */
  176. /*   If operand is one of { /first | /last | /next | /prev | /clear }      */
  177. /*   then it moves to the corresponding file in the chronological list     */
  178. /*   of identifiers tagged to, or it clears that list.                     */
  179.  
  180. void tag (~string)
  181.  
  182.  {  string tagstr, the_file, pattern, tag_path, tag_file, tag_dir;
  183.     string file_dir, curr_dir;
  184.     int buf, tagbuf, semi_spot, found = 0;
  185.     global tagstr;
  186.  
  187.     // Get tag to search for
  188.     if (! get_parm (0, tagstr, "Enter tag: ", NULL, tagstr))
  189.         return;
  190.  
  191.     buf = inq_buffer ();
  192.  
  193.     //-----------------------------------------------------------------------
  194.  
  195.     if (substr (tagstr, 1, 1) == "/")
  196.      {  // It's a navigation command
  197.  
  198.         string tag_line;
  199.         int chain_lines;
  200.  
  201.         if (! tag_chain_buffer)
  202.          {  error ("Couldn't install tag chaining.");
  203.             return;
  204.          }
  205.  
  206.         set_buffer (tag_chain_buffer);
  207.         end_of_buffer ();
  208.         move_abs (0,1);
  209.         tag_line = read ();
  210.         inq_position (chain_lines);
  211.         if (tag_line == "\n")
  212.             chain_lines--;
  213.  
  214.         if (! chain_lines)
  215.          {  error ("Nothing in tag chain.");
  216.             set_buffer (buf);
  217.             return;
  218.          }
  219.  
  220.         tagstr = lower (substr (tagstr, 2));
  221.         tagstr = ltrim (trim (tagstr));
  222.  
  223.         switch (tagstr)
  224.          { case "first":
  225.            case "f":
  226.             tag_chain_line = 1;
  227.             move_abs (tag_chain_line, 1);
  228.             tag_line = read ();
  229.             found = 1;
  230.  
  231.            case "last":
  232.            case "l":
  233.             tag_chain_line = chain_lines;
  234.             move_abs (tag_chain_line, 1);
  235.             tag_line = read ();
  236.             found = 1;
  237.  
  238.            case "next":
  239.            case "n":
  240.             if (tag_chain_line == chain_lines)
  241.                 error ("No next in tag chain.");
  242.             else
  243.              {  tag_chain_line++;
  244.                 move_abs (tag_chain_line, 1);
  245.                 tag_line = read ();
  246.                 found = 1;
  247.              }
  248.  
  249.            case "prev":
  250.            case "p":
  251.             if (tag_chain_line == 1)
  252.                 error ("No prev in tag chain.");
  253.             else
  254.              {  if (tag_chain_line == 0)
  255.                     tag_chain_line = chain_lines;
  256.                 else
  257.                     tag_chain_line--;
  258.                 move_abs (tag_chain_line, 1);
  259.                 tag_line = read ();
  260.                 found = 1;
  261.              }
  262.  
  263.            case "clear":
  264.            case "c":
  265.             top_of_buffer ();
  266.             drop_anchor (1);    // NORMAL_MARK
  267.             end_of_buffer ();
  268.             delete_block ();
  269.             tag_chain_line = 0;
  270.             message ("Tag chain has been cleared.");
  271.  
  272.            default:
  273.             error ("/%s is not a valid tag operand", tagstr);
  274.          }
  275.  
  276.         // go back to user's buffer
  277.         set_buffer  (buf);
  278.  
  279.         if (found)
  280.          {  // tag_line has info for switching to desired file
  281.  
  282.             parse_tag_line (tag_line, the_file, pattern);
  283.  
  284.             edit_file (the_file);
  285.  
  286.             end_of_buffer ();
  287.             if (search_back (pattern) <= 0)
  288.                 error ("Couldn't find \"%s\"",
  289.                                   substr (pattern, 2, strlen (pattern) - 2));
  290.             else
  291.                 center_line ();
  292.          }
  293.  
  294.         return;
  295.      }
  296.  
  297.     //-----------------------------------------------------------------------
  298.  
  299.     // Get directory stuff for searching
  300.     inq_names (file_dir);
  301.     getwd (NULL, curr_dir);
  302.     semi_spot = rindex (file_dir, "\\");
  303.     file_dir = substr (file_dir, 1, semi_spot-1);
  304.  
  305.     // Set up buffer for tag files
  306.     tagbuf = create_buffer ("tags", NULL, 1);
  307.     set_buffer (tagbuf);
  308.  
  309.     tag_file = TAGFILE;
  310.  
  311.     // If one exists, read the TAGFILE file from the current directory
  312.     if (exist(TAGFILE))
  313.      {  getwd (NULL, tag_dir);
  314.  
  315.         message ("Looking for tag %s in %s", tagstr, tag_dir);
  316.  
  317.         read_file (TAGFILE);
  318.  
  319.         move_abs (1, 1);
  320.  
  321.         if (search_fwd ("<" + tagstr + "[\t ]") > 0)
  322.          {  locate_in_file ();
  323.  
  324.             if (tagbuf != buf)
  325.                 delete_buffer (tagbuf);
  326.  
  327.             return;
  328.          }
  329.         else
  330.          {  message ("Tag %s not found in %s", tagstr, tag_dir);
  331.  
  332.             delete_buffer (tagbuf);
  333.             tagbuf = create_buffer ("tags", NULL, 1);
  334.             set_buffer (tagbuf);
  335.          }
  336.      }
  337.  
  338.     // Failing that, look in directory of file being edited (if different)
  339.     // Failing that, search for TAGFILE files in the TAGENV env variable path
  340.     tag_path = inq_environment (TAGENV);
  341.     if (file_dir != curr_dir)
  342.         tag_path = file_dir + ";" + tag_path;
  343.  
  344.     // Search tag_path
  345.     if (substr(tag_path, strlen(tag_path), 1) != ";")
  346.         tag_path = tag_path + ";";
  347.  
  348.     if (tag_path != "")
  349.      {  while (semi_spot = index (tag_path, ";"))
  350.          {  tag_dir = substr (tag_path, 1, semi_spot - 1);
  351.             tag_path = substr (tag_path, semi_spot + 1);
  352.             if (substr (tag_dir, strlen (tag_dir), 1) != "\\")
  353.                 tag_dir = tag_dir + "\\";
  354.  
  355.             message ("Looking for tag %s in %s", tagstr, tag_dir);
  356.  
  357.             if (inq_kbd_char ())   /*  see if any keys pressed  */
  358.              {  read_char ();      /*   swallow the key  */
  359.                 message ("Aborted search for tag %s before %s", 
  360.                                                             tagstr, tag_dir);
  361.                 set_buffer (buf);
  362.                 if (tagbuf != buf)
  363.                     delete_buffer (tagbuf);
  364.                 return;
  365.              }
  366.  
  367.             tag_file = tag_dir + TAGFILE;
  368.             read_file(tag_file);
  369.  
  370.             move_abs (1, 1);
  371.  
  372.             if (search_fwd ("<" + tagstr + "[\t ]") > 0)
  373.              {  locate_in_file ();
  374.  
  375.                 found = 1;
  376.                 break;
  377.              }
  378.             else
  379.              {  message ("Tag %s not found in %s", tagstr, tag_dir);
  380.  
  381.                 delete_buffer (tagbuf);
  382.                 tagbuf = create_buffer ("tags", NULL, 1);
  383.                 set_buffer (tagbuf);
  384.              }
  385.          }
  386.      }
  387.  
  388.     if (! found)
  389.      {  message ("Tag %s not found", tagstr);
  390.         set_buffer (buf);
  391.      }
  392.  
  393.     if (tagbuf != buf)
  394.         delete_buffer (tagbuf);
  395.  
  396.     return;
  397.  }
  398.  
  399. //---------------------------------------------------------------------------
  400.  
  401. void ctag (void)
  402.  
  403.  {  string tagstr;
  404.  
  405.     tagstr = GetIdentifier ("a-zA-Z0-9_");
  406.  
  407.     if (tagstr == "")
  408.         error ("Not on valid identifier.");
  409.     else 
  410.         tag (tagstr);
  411.  
  412.     return;
  413.  }
  414.  
  415. //---------------------------------------------------------------------------
  416.  
  417. void locate_in_file (void)
  418.  
  419.  {  string tag_line, the_file, pattern;
  420.  
  421.     // We are in the TAGFILE buffer, and will switch to the file-to-be-edited
  422.     //  at the end of this
  423.  
  424.     tag_line = read ();   // save the tag line for the chain file
  425.  
  426.     message ("tag_line = <%s>", tag_line);
  427.  
  428.     // tag_line has info for switching to desired file
  429.     // analyze the tag line: "tag file pattern"
  430.     parse_tag_line (tag_line, the_file, pattern);
  431.  
  432.     // insert the tag line in place in the chain file
  433.     set_buffer (tag_chain_buffer);
  434.     tag_chain_line++;
  435.     move_abs (tag_chain_line, 1);
  436.     insert (tag_line);
  437.  
  438.     // switch to the tagged file
  439.     edit_file (the_file);
  440.     end_of_buffer ();
  441.  
  442.     // and find the function header
  443.     if (search_back (pattern) <= 0)
  444.         error ("Couldn't find \"%s\"",
  445.                                   substr (pattern, 2, strlen (pattern) - 2));
  446.     else
  447.         center_line ();
  448.  
  449.     return;
  450.  }
  451.  
  452. /****************************************************************************
  453. *
  454. *   parse_tag_line                                      28Oct92
  455. *
  456. *   tag_line has info for switching to desired file
  457. *    we have the line in hand:
  458. *        "tagstr the_file pattern"
  459. *
  460. *   Returns "the_file" and "pattern"
  461. *
  462. *   Change History:
  463. *   Date    Who What
  464. *   ------- --- -------------
  465. *   28Oct92 BAG First draft
  466. *
  467. ****************************************************************************/
  468.  
  469. void parse_tag_line (string tag_line, string the_file, string pattern)
  470.  
  471.  {  int posn;
  472.     string loc_the_file, loc_pattern;
  473.  
  474.     // Throw away "tagstr"
  475.     posn = search_string ("[\t ]", tag_line);
  476.     tag_line = substr (tag_line, posn+1);
  477.  
  478.     // Throw away blanks between "tagstr" and "the_file"
  479.     posn = search_string ("[~\t ]", tag_line);
  480.     tag_line = substr (tag_line, posn);
  481.  
  482.     // Get "the_file"
  483.     posn = search_string ("[\t ]", tag_line);
  484.     loc_the_file = substr (tag_line, 1, posn-1);
  485.  
  486.     // Remove it and blanks from it to pattern from what's left of tag_line
  487.     tag_line = substr (tag_line, posn+1);
  488.     posn = search_string ("[~\t ]", tag_line);
  489.     loc_pattern = substr (tag_line, posn);
  490.  
  491.     // Strip off leading "?" and final "?\n" from pattern
  492.     loc_pattern = substr (loc_pattern, 2, strlen (loc_pattern) - 3);
  493.  
  494.     // Return the values
  495.     put_parm (1, loc_the_file);
  496.     put_parm (2, loc_pattern);
  497.  
  498.     return;
  499.  }
  500.  
  501. /************************ end of ctags.cb file *****************************/
  502.